﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp.MyLinq.Misc
{
    public class ExpressionTakeRestrainer : ExpressionVisitor
    {
        private int maxTake;
        public bool ExpressionHasTake { get; private set; }

        public Expression ParseAndConstrainTake(Expression expression, int maxTake)
        {
            this.maxTake = maxTake;
            ExpressionHasTake = false;
            return Visit(expression);
        }

        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node.Method.Name == nameof(Enumerable.Take))
            {

                // Enumerable.Take 的签名
                // 两个参数
                // (IEnumerable<TSource> source, int count)

                ExpressionHasTake = true;
                if (node.Arguments.Count == 2 && node.Arguments[1] is ConstantExpression constant)
                {
                    var takeCount = (int)constant.Value;
                    if (takeCount > maxTake)
                    {
                        // 此处递归调用，重写所有的 Take
                        var arg1 = Visit(node.Arguments[0]);
                        // 下面不递归调用，将只重写最外的一个 Take
                        //var arg1 = node.Arguments[0];
                        var arg2 = Expression.Constant(maxTake);
                        var methodCall = Expression.Call(node.Object, node.Method, new[] { arg1, arg2 });
                        return methodCall;
                    }
                }
            }
            return base.VisitMethodCall(node);
        }
    }
}
